package bosc.cn.service.impl;

import bosc.cn.RustSignReqDTO;
import bosc.cn.RustSignResDTO;
import bosc.cn.RustVerifyReqDTO;
import bosc.cn.RustVerifyResDTO;
import bosc.cn.mapper.WalletUserInfoMapper;
import bosc.cn.model.WalletUserInfo;
import bosc.cn.service.SignService;
import bosc.cn.tunnel.SignServiceTunnelClient;
import cn.dto.SignRequest;
import cn.dto.SignResponse;
import cn.dto.VerifyRequest;
import cn.dto.VerifyResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @author chengcheng
 * @date 2025/9/8 20:57
 * @description
 */

@Service
@Slf4j
public class SignServiceImpl implements SignService {
    public static final int RUST_PORT = 18080;
    @Autowired
    private SignServiceTunnelClient tunnelClient;

    @Autowired
    @Qualifier("signThreadPool")
    private Executor threadPool;


    @Autowired
    private WalletUserInfoMapper walletUserInfoMapper;

    // 真实请求的两个硬件id和ip
    int[] realIndexArray = new int[2];
    String[] realIpArray = new String[2];
    String[] realPorts = new String[2];

    // 公钥（point）
    public static final String PUBLIC_KEY = "021f22c711f2cb0990e877b04c64811847fe72a572638137f293ebfcbba985cc1b";

    /**
     * 签名
     * 通过代理服务器穿透内网调用rust-service
     *
     * @param req
     * @return
     */
    @Override
    public SignResponse sign(SignRequest req) {

        SignResponse signResponse = new SignResponse();

        // 获取授权人列表，优先选择前两个审批人
        List<String> authList = req.getAuthList();
        if (authList == null || authList.size() < 2) {
            signResponse.setPrcSts("PR99");
            signResponse.setPrcMsg("至少需要两个授权人签名");
            return signResponse;
        }

        // 取前两个授权人
        authList = authList.subList(0, 2);

        // 设置真实ip和id
        String[] aeads = setRealIdAndIp(authList, req.getWltId());
        // 提交两个异步任务
        List<CompletableFuture<RustSignResDTO>> futures = new ArrayList<>();
        for (int i = 0; i < 2; i++) {

            // 构造 RustSignReqDTO
            RustSignReqDTO rustReq = new RustSignReqDTO();
            rustReq.setLocalId(realIndexArray[i]);                // 本地节点ID
            rustReq.setPeerId(realIndexArray[1 - i]);             // 对方节点ID
            rustReq.setMessage(req.getAuthInfo());    // 签名内容
            rustReq.setLocalIp(realIpArray[i]);  // 本地IP
            rustReq.setPeerIp(realIpArray[1 - i]); // 对方IP
            rustReq.setLocalPort(Integer.parseInt(realPorts[i]));   // 本地端口
            rustReq.setPeerPort(Integer.parseInt(realPorts[1 - i])); // 对方端口

            // 使用异步调用
            CompletableFuture<RustSignResDTO> future = null;
            try {
                // future 放 callRustSign里面会导致线程阻塞，无法并发执行
                future = tunnelClient.callRustSign(rustReq, realIndexArray[i]);
            } catch (Exception e) {
                e.printStackTrace();
            }
            futures.add(future);

        }

        try {
            // 等待同时完成

            CompletableFuture<Void> allFutures = CompletableFuture.allOf(
                    futures.toArray(new CompletableFuture[0])
            );

            try {
                allFutures.get(60, TimeUnit.SECONDS); // 最多等待60秒
            } catch (TimeoutException e) {
                signResponse.setPrcSts("PR88");
                signResponse.setPrcMsg("签名处理中，超时未返回结果");
                return signResponse;
            }

            // 获取结果
            RustSignResDTO result0 = futures.get(0).get();
            RustSignResDTO result1 = futures.get(1).get();

            // 检查结果
            if (result0 == null || result1 == null) {
                signResponse.setPrcSts("PR77");
                signResponse.setPrcMsg("签名失败，有授权人未返回结果");
                return signResponse;
            }

            // 验证两个审批人生成的 r、s 是否一致
            if (result0.getR() == null || result0.getS() == null || result1.getR() == null || result1.getS() == null) {
                signResponse.setPrcSts("PR66");
                signResponse.setPrcMsg("签名结果缺失 r 或 s");
                return signResponse;
            }

            if (!result0.getR().equals(result1.getR())) {
                signResponse.setPrcSts("PR55");
                signResponse.setPrcMsg("两位审批人生成的 r 不一致");
                return signResponse;
            }

            if (!result0.getS().equals(result1.getS())) {
                signResponse.setPrcSts("PR44");
                signResponse.setPrcMsg("两位审批人生成的 s 不一致");
                return signResponse;
            }


            // AEAD 校验
            if (!aeads[0].equals(result0.getAead())) {
                signResponse.setPrcSts("PR22");
                signResponse.setPrcMsg("审批人 " + authList.get(0) + " 的 AEAD 与硬件key不一致");
                return signResponse;
            }

            if (!aeads[1].equals(result1.getAead())) {
                signResponse.setPrcSts("PR11");
                signResponse.setPrcMsg("审批人 " + authList.get(0) + " 的 AEAD 与硬件key不一致");
                return signResponse;
            }


            // 两个签名都返回
            signResponse.setPrcSts("PR00");
            signResponse.setPrcMsg("签名成功");
            signResponse.setAuthMsg(result0.getR() + result0.getS());
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            signResponse.setPrcSts("PR89");
            signResponse.setPrcMsg("签名处理中，线程被中断");
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        return signResponse;

    }

    // 根据请求的授权人列表，设置真实请求的硬件id和ip
    private String[] setRealIdAndIp(List<String> authList, String wltId) {

        // 根据输入userId和钱包id查领用记录表找硬件标识
        LambdaQueryWrapper<WalletUserInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WalletUserInfo::getWltId, wltId);
        queryWrapper.eq(WalletUserInfo::getUserId, authList.get(0));
        WalletUserInfo walletUserInfo0 = walletUserInfoMapper.selectOne(queryWrapper);
        queryWrapper.clear();
        queryWrapper.eq(WalletUserInfo::getWltId, wltId);
        queryWrapper.eq(WalletUserInfo::getUserId, authList.get(1));
        WalletUserInfo walletUserInfo1 = walletUserInfoMapper.selectOne(queryWrapper);

        if(walletUserInfo0==null){
            throw new RuntimeException("钱包 " + wltId + " 未领用授权人 " + authList.get(0));
        }
        if(walletUserInfo1==null){
            throw new RuntimeException("钱包 " + wltId + " 未领用授权人 " + authList.get(1));
        }
        // 第一个授权人对应钱包的硬件key
        String subWltKey0 = walletUserInfo0.getSubWltKey();
        // 第二个授权人对应钱包的硬件key
        String subWltKey1 = walletUserInfo1.getSubWltKey();

        String[] aeads = new String[2];
        aeads[0] = subWltKey0;
        aeads[1] = subWltKey1;
        realIndexArray[0] = Integer.parseInt(walletUserInfo0.getWltIndex());
        realIndexArray[1] = Integer.parseInt(walletUserInfo1.getWltIndex());
        realIpArray[0] = walletUserInfo0.getWltIp();
        realIpArray[1] = walletUserInfo1.getWltIp();
        realPorts[0] = walletUserInfo0.getWltPort();
        realPorts[1] = walletUserInfo1.getWltPort();

        return aeads;
    }

    @Override
    public VerifyResponse verify(VerifyRequest req) {

        System.out.println(">>>> SignServiceImpl.verifyTest 被调用, 参数: " + req);
        VerifyResponse verifyResponse = new VerifyResponse();

        try {

            // 共同授权信息密文校验
            if (req.getAuthMsg() == null || req.getAuthMsg().trim().isEmpty()) {
                verifyResponse.setPrcSts("PR99");
                verifyResponse.setPrcMsg("共同授权信息密文为空");
                return verifyResponse;
            }

            // 共同授权信息校验
            if (req.getAuthInfo() == null || req.getAuthInfo().trim().isEmpty()) {
                verifyResponse.setPrcSts("PR88");
                verifyResponse.setPrcMsg("共同授权信息为空");
                return verifyResponse;
            }

            // 获取授权人列表，优先选择前两个审批人
            List<String> authList = req.getAuthList();
            if (authList == null || authList.size() < 2) {
                verifyResponse.setPrcSts("PR77");
                verifyResponse.setPrcMsg("至少需要两个授权人签名");
                return verifyResponse;
            }

            // 取前两个授权人
            authList = authList.subList(0, 2);
            // 设置真实请求的硬件id和ip
            setRealIdAndIp(authList, req.getWltId());

            // 调用 rust-service 验签,似乎不需要调用两次
            //for (int i = 0; i < 2; i++) {
            RustVerifyReqDTO rustReq = new RustVerifyReqDTO();
            // req.getAuthMsg() 从中间截取，前一半赋值给r，后一半赋值给s，后一半赋值给s
            rustReq.setR(req.getAuthMsg().substring(0, req.getAuthMsg().length() / 2));

            rustReq.setS(req.getAuthMsg().substring(req.getAuthMsg().length() / 2));
            RustVerifyResDTO rustVerify = tunnelClient.callRustVerify(rustReq, realIndexArray[0]);
            System.out.println(">>>> rustRes: " + rustVerify);

            if (!rustVerify.isValid()) {
                verifyResponse.setPrcSts("PR66");
                verifyResponse.setPrcMsg("验签失败：审批人的签名无效");
                return verifyResponse;
            }
        } catch (Exception e) {
            // 出现异常，通信失败
            throw new RuntimeException("通信失败", e);
        }


        // 验签都通过
        verifyResponse.setPrcSts("PR00");
        verifyResponse.setPrcMsg("验签成功");


        return verifyResponse;
    }

}
